<script setup lang="ts">
import store from "@/store";
import { ref, computed, watch } from "vue";
import { ModuleType } from "@/type";
import { deepClone } from "@/utils/utils";
import { addNode, copyNode, deleteNode, getTargetNode } from "@/utils/tool";
import XmlList from "@/components/xmlList/index.vue";
import XmlGroup from "@/components/xmlGroup/index.vue";
import { ElMessage } from "element-plus";

const centerContentRef = ref();
const xmlGroupRef = ref();
const addNodeStyle = ref({ top: 0, left: 0, width: 0 });
const addNodeIndex = ref(0);

// 模块列表
const moduleList = computed(() => {
  return store.getters.moduleList;
});
// 拖拽组件
const dragComponent = computed(() => {
  return store.getters.dragComponent;
});
// 当前节点
const currentNode = computed(() => {
  return store.getters.currentNode;
});
// 添加节点时的样式
const addNodeLineStyle = computed(() => {
  return {
    top: addNodeStyle.value.top + "px",
    left: addNodeStyle.value.left + "px",
    width: addNodeStyle.value.width + "px"
  };
});
// 没有拖拽时，将宽度修改为0
watch(dragComponent, () => {
  if (!dragComponent.value.id) {
    addNodeStyle.value.width = 0;
    addNodeIndex.value = 0;
  }
});

/**
 * 拖拽放置目标
 */
const dragover = (e: any) => {
  if (!dragComponent.value.id) return;
  e.preventDefault();
  // 目标
  const target = e.toElement.closest(".xml-node");
  if (target) {
    // 目标位置
    const clientRect = target.getBoundingClientRect();
    // 目标索引
    const index = Number(target.dataset.index || 0);
    // 布局节点
    if (target.dataset.layout) {
      // 布局节点下半
      if (e.clientY > clientRect.y + clientRect.height / 2) {
        addNodeStyle.value.top = clientRect.y + clientRect.height - 10;
        addNodeIndex.value = -1;
      } else {
        // 布局节点上半
        addNodeStyle.value.top = clientRect.y + 40;
        addNodeIndex.value = 0;
      }
    } else {
      // 节点下半
      if (e.clientY > clientRect.y + clientRect.height / 2) {
        addNodeStyle.value.top = clientRect.y + clientRect.height;
        addNodeIndex.value = index + 1;
      } else {
        // 节点上半
        addNodeStyle.value.top = clientRect.y;
        addNodeIndex.value = index;
      }
    }
    addNodeStyle.value.left = clientRect.x;
    addNodeStyle.value.width = clientRect.width;
  }
};
/**
 * 拖拽放置目标
 */
const drop = (e: any) => {
  if (!dragComponent.value.id) return;
  let targetId = "";
  // 目标
  const target = e.toElement.closest(".xml-node");
  if (target && target.dataset && target.dataset.id) {
    if (target.dataset.layout) {
      // 当前目标是布局组件
      targetId = target.dataset.id;
    } else {
      // 当前目标不是布局组件时，寻找父组件是布局组件
      const parent = target.parentElement.closest(".xml-node");
      if (parent && parent.dataset && parent.dataset.id && parent.dataset.layout) {
        targetId = parent.dataset.id;
      }
    }
  }
  // 获取当前目标节点
  const targetNode = getTargetNode(moduleList.value, targetId);
  // 节点最大子集数
  if (targetNode.layout && targetNode.childrenMax && targetNode.children.length >= Number(targetNode.childrenMax)) {
    ElMessage.error("已到达节点最大子集数，不可再拖入子组件");
    return;
  }
  // 当前节点
  const node = deepClone(dragComponent.value);
  // 设置节点
  const list = addNode(moduleList.value, targetId, node, addNodeIndex.value);
  store.commit("setModuleList", list);
  store.commit("setCurrentNode", node);
  locationCurrentNode();
};
/**
 * 定位当前节点
 */
const locationCurrentNode = () => {
  setTimeout(() => {
    const currentNodeEl = document.getElementById(currentNode.value.id);
    if (!currentNodeEl) return;
    const clientRect = currentNodeEl.getBoundingClientRect() as any;
    if (clientRect.y > window.innerHeight) {
      // 不在可视区中
      centerContentRef.value.scrollTop += clientRect.y - 60;
    }
  }, 100);
};
/**
 * 复制节点
 */
const copyNodeFn = (module: ModuleType) => {
  const list = copyNode(moduleList.value, module.id);
  store.commit("setModuleList", list);
};
/**
 * 删除节点
 */
const deleteNodeFn = (module: ModuleType) => {
  const list = deleteNode(moduleList.value, module.id);
  store.commit("setModuleList", list);
  store.dispatch("clearCurrentNode");
};
/**
 * 组合节点
 */
const groupNodeFn = (module: ModuleType) => {
  xmlGroupRef.value.open(module);
};
</script>

<template>
  <div ref="centerContentRef" class="center-content">
    <div class="workspace" @dragover="dragover" @drop="drop">
      <XmlList :list="moduleList" @copy-node="copyNodeFn" @delete-node="deleteNodeFn" @group-node="groupNodeFn" />
    </div>
    <div class="add-node-line" :style="addNodeLineStyle"></div>
    <XmlGroup ref="xmlGroupRef" />
  </div>
</template>
